'''
Created on 2011-04-25

@author: kacper
'''
from dataStructs.definitions import *
from logger.logger import instLog, instLogFun


log = instLog("Transform")
logFun = instLogFun(log)


class Multile(Formula):
    def __init__(self,lst):
        self.fs =lst
        
    def prt(self, spec=0,delmiter=" "):
        try:
            return  "["+ delmiter.join( map( lambda x: x.prt(spec),self.fs)) + "]"
        except Exception:
            print "err NNNNNNNNNNNNNNNNNNNNNNNNNN \n"
            print self.fs
            return str(self.fs)
            
class MultipleOr(Multile):
    def __init__(self,lst = None):
        if not lst: lst = []
        super(MultipleOr,self).__init__(lst)

    def prt(self, spec =0):
        return super(MultipleOr, self).prt(spec," , ")
    
class MultipleAnd(Multile):
    @logFun
    def __init__(self, lst =None):
        log( "const ", str(lst) )
        if lst == None: lst = []
        super(MultipleAnd,self).__init__(lst)
 

    def prt(self, spec=0):
        return super(MultipleAnd, self).prt(spec," , ")

@logFun    
def subclsAnd(x):
    f1 = cnf(x.f1)
    log( "f1>>", f1)
    f2 = cnf(x.f2)
    log( "f2>>", f2)
    cf1 = f1.__class__
    cf2 = f2.__class__
    
    log( "and ",f1,f2," dna ")
    
    if(cf1 == cf2 and cf1 == MultipleAnd):
        f1.fs += f2.fs
        log( "1 " ,f1)
        return f1
    
    elif (cf1 == cf2 and cf2==MultipleOr):
        a = MultipleAnd()
        log( "a >>" ,a)
        a.fs += [f1,f2]
        log( "2 " ,a)
        return a
    
    elif ( cf2==MultipleOr ):
        f1.fs += [f2]
        log( "3 " ,f1)
        return f1
    
    else:
        f2.fs += [f1]
        log( "4 " ,f2)
        return f2 
    
    
    
def subclsOr(x):
    f1 = cnf(x.f1)
    
    f2 = cnf(x.f2)
    
    cf1 = f1.__class__
    cf2 = f2.__class__
    
    log( "f1 ",f1)
    log( "f2 ",f2)
    
    
    if   (cf1 == cf2 and cf1 == MultipleAnd):
       
        tab = [ [ x.fs+y.fs for x in f1.fs] for y in f2.fs  ]
        
        tab = sum(tab,[])
        tab = map( lambda x: MultipleOr(lst = x) , tab )
        return MultipleAnd(lst = tab)
    
    elif (cf1 == cf2 and cf2==MultipleOr):
        return MultipleOr(lst = f1.fs+f2.fs)
    
    elif ( cf2==MultipleOr ):
        f1,f2 = f2,f1
    

    tabAnd = f2.fs
    tabAnd = map( lambda x: f1.fs+x.fs , tabAnd)
    log("tabAnd", tabAnd)
    tabAnd = map( lambda x: MultipleOr(lst = x) , tabAnd )
    return MultipleAnd(lst = tabAnd)
    
def MultipleToList(x):
    if isinstance(x, MultipleAnd):
        return map( lambda x: x.fs ,x.fs)
    return [ x.fs ]      
    
    
def cnf( x ):
    cls = x.__class__
#    if cls == Formula:
#        return cnf(x.FOformula)
    if cls == BinFormula:
        #TODO raise error
        return 0
    elif cls == Default:
        return Default(cnf(x.f1), cnf(x.f2))
    elif cls == AndFormula:
        return subclsAnd(x)
    elif cls == OrFormula:
        return subclsOr(x)
    else :
        return MultipleOr(lst = [x])


    
 
if __name__ == "__main__":
    from test.RandomFromula import genFormula
    for x in xrange(100):
        r = genFormula()
        print "plain formula ", r
        r =r.removeThen().pushNeg()
        print "neq push plain formula ", r
        print "cnf formula " , cnf(r)  
        if ( cnf(r) == None ): raise Exception()
        log ("next")
        log("plain formula ", r)
        log("cnf formula " , cnf(r))
        
#def _cnf(x):
     

